// created on 04.08.2007 at 12:55
using System;
using System.Text.RegularExpressions;

namespace Gamadus.Engine
{
	public static class Gml
	{		
		#region Math
		public static real round(GmlVar x)
		{
			return Math.Round(x.GetDouble());
		}
		public static real floor(GmlVar x)
		{ 
			return Math.Floor(x.GetDouble());
		}
		public static real ceil(GmlVar x)
		{
			return Math.Ceiling(x.GetDouble());
		}
		public static real sign(GmlVar x)
		{
			return Math.Sign(x.GetDouble());
		}
		public static GmlVar choose(params GmlVar[] values)
		{
			return values[Engine.Instance.random.Next(values.Length)];
		}
		public static real point_direction(GmlVar x1, GmlVar y1, GmlVar x2, GmlVar y2)
		{
			double d = Math.Atan2(y1.GetDouble()-y2.GetDouble(),x2.GetDouble()-x1.GetDouble())*180/Math.PI;
			d = (d < 0) ? d+360 : d;
			return (real) d;
		}
		
		public static real point_distance(GmlVar x1, GmlVar y1, GmlVar x2, GmlVar y2)
		{
			return (real) Math.Sqrt( Math.Pow(x2.GetDouble()-x1.GetDouble(),2) + Math.Pow(y2.GetDouble()-y1.GetDouble(),2));
		}
		
		public static real lengthdir_x(GmlVar r, GmlVar dir)
		{
		return (real) Math.Cos( dir.GetDouble() / 180 * Math.PI) * r.GetDouble();
		}
		
		public static real lengthdir_y(GmlVar r, GmlVar dir)
		{
		return -((real) Math.Sin( dir.GetDouble() / 180 * Math.PI) * r.GetDouble());
		}
		
		public static real abs(GmlVar x)
		{
		return (real) Math.Abs(x.GetDouble());
		}

		public static real sqrt(GmlVar x)
		{
		return (real) Math.Sqrt(x.GetDouble());
		}

		public static real sqr(GmlVar x)
		{
		return (real) x.GetDouble()*x.GetDouble();
		}

		public static real power(GmlVar n, GmlVar x)
		{
		return (real) Math.Pow(n.GetDouble(),x.GetDouble());
		}

		public static real exp(GmlVar x)
		{
		return (real) Math.Pow(Math.E,x.GetDouble());
		}

		public static real ln(GmlVar x)
		{
		return (real) Math.Log(x.GetDouble());
		}

		public static real log2(GmlVar x)
		{
		return (real) Math.Log(x.GetDouble(), 2);
		}

		public static real log10(GmlVar x)
		{
		return (real) Math.Log10(x.GetDouble());
		}

		public static real logn(GmlVar n, GmlVar x)
		{
		return (real) Math.Log(x.GetDouble(), n.GetDouble());
		}

		public static real sin(GmlVar x)
		{
		return (real) Math.Sin(x.GetDouble());
		}

		public static real cos(GmlVar x)
		{
		return (real) Math.Cos(x.GetDouble());
		}

		public static real tan(GmlVar x)
		{
		return (real) Math.Tan(x.GetDouble());
		}

		public static real arcsin(GmlVar x)
		{
		return (real) Math.Asin(x.GetDouble());
		}

		public static real arccos(GmlVar x)
		{
		return (real) Math.Acos(x.GetDouble());
		}

		public static real arctan(GmlVar x)
		{
		return (real) Math.Atan(x.GetDouble());
		}

		public static real arctan2(GmlVar y, GmlVar x)
		{
		return (real) Math.Atan2(y.GetDouble(), x.GetDouble());
		}

		public static real degtorad(GmlVar x)
		{
		return (real) x.GetDouble()/180*Math.PI;
		}

		public static real radtodeg(GmlVar x)
		{
		return (real) x.GetDouble()/Math.PI*180;
		}
		
		public static real frac(GmlVar x)
		{
		return (real) Math.Sign(x.GetDouble())*(x.GetDouble()-Math.Floor(x.GetDouble()));
		}
		
		public static real random(GmlVar x)
		{
			int maxint = (int) Math.Floor(x.GetDouble());
			double d = Engine.Instance.random.NextDouble();
			if(d == 1)
				d = 0;
			double maxdouble = x.GetDouble()-Math.Floor(x.GetDouble());
			if(maxdouble == 0)
				d = 0;
			else
				d = d % maxdouble;
			return Engine.Instance.random.Next(maxint)+d;
		}
		
		public static GmlVar min(params GmlVar[] values)
		{
			if(values[0].Value is real)
			{
				double dmin = values[0].GetDouble();
				foreach(GmlVar r in values)
				{
					dmin = Math.Min(r.GetDouble(), dmin);
				}
				return (real)dmin;
			}
			else
			{
				string smin = values[0].GetString();
				foreach(GmlVar s in values)
				{
					smin = (String.Compare(s.GetString(),smin) < 0)?s.GetString():smin;
				}
				return smin;
			}
		}
		public static GmlVar max(params GmlVar[] values)
		{
			if(values[0].Value is real)
			{
				double dmin = values[0].GetDouble();
				foreach(GmlVar r in values)
				{
					dmin = Math.Max(r.GetDouble(), dmin);
				}
				return (real)dmin;
			}
			else
			{
				string smin = values[0].GetString();
				foreach(GmlVar s in values)
				{
					smin = (String.Compare(s.GetString(),smin) > 0)?s.GetString():smin;
				}
				return smin;
			}
		}
		public static real mean(params GmlVar[] values)
		{
			double d = 0;
			foreach(GmlVar r in values)
			{
				d+=r.GetDouble();
			}
			
			return (real)(d/(double)values.Length);
		}
		public static real median(params GmlVar[] values)
		{
			System.Collections.Generic.List<double> list = new System.Collections.Generic.List<double>();
			foreach(GmlVar r in values)
			{
				list.Add(r.GetDouble());
			}
			list.Sort();
			int index = (int)Math.Ceiling((double)values.Length/2) -1;
			return (real)(list[index]);
		}
		#endregion
		
		#region Types
		public static real is_real(GmlVar o)
		{
			return (o.Value is real);
		}
		public static real is_string(GmlVar o)
		{
			return (o.Value is string);
		}
		
		public static real real(GmlVar val)
		{
			double d = double.Parse(val.GetString(), System.Globalization.CultureInfo.InvariantCulture);
			return (real)(d);
		}
		public static string @string(GmlVar val)
		{
			return val.ToString();
		}
		#endregion
		
		#region String
		public static string chr(GmlVar val)
		{
			char c = (char) (int)val.GetDouble();
			return c.ToString();
		}
		public static real ord(GmlVar @char)
		{
			char c = (char)@char.GetString().Substring(0,1).ToCharArray()[0];
			return (real)((int)c);
		}
		public static string string_format(GmlVar val, GmlVar total, GmlVar dec)
		{
			string s = String.Format(System.Globalization.CultureInfo.InvariantCulture,"{0:F"+(int)dec.GetDouble()+"}", val.GetDouble() );
			while(s.Length < (int)total.GetDouble())
				s = " "+s;
			return s;
		}
		public static real string_length(GmlVar str)
		{
			return (real)(str.GetString().Length);
		}
		public static real string_pos(GmlVar substr, GmlVar str)
		{
			return (real)(str.GetString().IndexOf(substr.GetString()) +1);
		}
		public static string string_copy(GmlVar str, GmlVar index, GmlVar count)
		{
			int _index = (int)index.GetDouble();
			if(_index < 1)
				_index = 1;
			int _count = (int)count.GetDouble();
			if(_index+_count > str.GetString().Length)
				_count = str.GetString().Length - _index+1;
			return str.GetString().Substring(_index-1, _count);
		}
		public static string string_delete(GmlVar str, GmlVar index, GmlVar count)
		{
			int _index = (int)index.GetDouble();
			if(_index < 1)
				return str.GetString();
			int _count = (int)count.GetDouble();
			if(_index+_count > str.GetString().Length)
				_count = str.GetString().Length-_index+1;
			return str.GetString().Remove(_index-1, _count);
		}
		public static string string_char_at(GmlVar str, GmlVar index)
		{
			int _index = (int)index.GetDouble();
			if(_index < 1)
				_index = 1;
			if(_index > str.GetString().Length)
				_index = str.GetString().Length;
			return str.GetString().Substring(_index-1, 1);
		}
		public static string string_insert(GmlVar substr, GmlVar str, GmlVar index)
		{
			int _index = (int)index.GetDouble();
			if(_index < 1) 
				_index = 1;
			if(_index > str.GetString().Length)
				_index = str.GetString().Length +1;
			return str.GetString().Insert(_index-1, substr.GetString());
		}
		public static string string_upper(GmlVar str)
		{
			return str.GetString().ToUpper();
		}
		public static string string_lower(GmlVar str)
		{
			return str.GetString().ToLower();
		}
		
		public static real string_count(GmlVar substr, GmlVar str)
		{
			int occur = 0;
			int ind;
			while((ind = str.GetString().IndexOf(substr.GetString())) > -1)
			{
				occur++;
				str = str.GetString().Remove(ind, substr.GetString().Length);
			}
			return (real)(occur);
		}
		
		public static string string_repeat(GmlVar str, GmlVar count)
		{
			int _count = (int)count.GetDouble();
			string returnstr = str.GetString();
			if(_count < 1)
				return "";
			while(_count > 1)
			{
				returnstr +=str.GetString();
				_count--;
			}
			return returnstr;
		}
		public static string string_replace(GmlVar str, GmlVar substr, GmlVar newstr)
		{
			int index = str.GetString().IndexOf(substr.GetString());
			string returnstr = str.GetString().Remove(index, substr.GetString().Length);
			returnstr = returnstr.Insert(index, newstr.GetString());
			return returnstr;
		}
		public static string string_replace_all(GmlVar str, GmlVar substr, GmlVar newstr)
		{
			return str.GetString().Replace(substr.GetString(), newstr.GetString());
		}
		public static string string_letters(GmlVar str)
		{
			string returnstr = "";
			foreach(Match match in Regex.Matches(str.GetString(), "[A-Za-z]"))
			{
				returnstr += match.Value;
			}
			return returnstr;
		}
		public static string string_digits(GmlVar str)
		{
			string returnstr = "";
			foreach(Match match in Regex.Matches(str.GetString(), "[0-9]"))
			{
				returnstr += match.Value;
			}
			return returnstr;
		}
		public static string string_lettersdigits(GmlVar str)
		{
			string returnstr = "";
			foreach(Match match in Regex.Matches(str.GetString(), "[A-Za-z0-9]"))
			{
				returnstr += match.Value;
			}
			return returnstr;
		}
		#endregion
		
		#region Input
		#region Keyboard
		public static real keyboard_check(GmlVar key)
		{
			return InputMgr.Instance.KeyboardCheck((int)key.GetDouble());
		}
		public static real keyboard_check_pressed(GmlVar key)
		{
			return InputMgr.Instance.KeyboardCheckPressed((int)key.GetDouble());
		}
		public static real keyboard_check_released(GmlVar key)
		{
			return InputMgr.Instance.KeyboardCheckReleased((int)key.GetDouble());
		}
		#endregion
		
		#region Mouse
		
		#endregion
		#endregion

		#region Draw
//		public static void draw_set_font(Font f)
//		{
//			DrawMgr.Instance.CurrentFont = f;
//		}
//		public static void draw_text(GmlVar x, GmlVar y, string str)
//		{
//			if(!DrawMgr.Instance.DrawEvent) return;
//			if(DrawMgr.Instance.CurrentFont == null)
//				throw new NullReferenceException("No Font is set, set on by using draw_set_font");
//			
//			//TODO!
////			SdlDotNet.Graphics.Surface fontSurface = DrawMgr.Instance.currentFont.font.Render(str, DrawMgr.Instance.currentColor,false);
////			SdlDotNet.Graphics.Video.Screen.Blit(fontSurface,new System.Drawing.Point(x,y));
//		}
//		public static void draw_set_color(System.Drawing.Color col)
//		{
//			DrawMgr.Instance.CurrentColor = col;
//		}
//		public static System.Drawing.Color draw_get_color()
//		{
//			return DrawMgr.Instance.CurrentColor;
//		}
		public static void draw_point(GmlVar x, GmlVar y)
		{
			System.Drawing.Point p = new System.Drawing.Point((int)x.GetDouble(),(int)y.GetDouble());
			DrawMgr.DrawPoint(p);
		}
		public static void draw_line(GmlVar x1, GmlVar y1, GmlVar x2, GmlVar y2)
		{
			System.Drawing.Point p1 = new System.Drawing.Point((int)x1.GetDouble(),(int)y1.GetDouble());
			System.Drawing.Point p2 = new System.Drawing.Point((int)x2.GetDouble(),(int)y2.GetDouble());
			DrawMgr.DrawLine(p1,p2);
		}
		public static void draw_rectangle(GmlVar x1, GmlVar y1, GmlVar x2, GmlVar y2, GmlVar outline)
		{
			System.Drawing.Point p1 = new System.Drawing.Point((int)x1.GetDouble(),(int)y1.GetDouble());
			System.Drawing.Point p2 = new System.Drawing.Point((int)x2.GetDouble(),(int)y2.GetDouble());
			DrawMgr.DrawRectangle(p1,p2,!(bool)outline);
		}
		public static void draw_circle(GmlVar x, GmlVar y, GmlVar r, GmlVar outline)
		{
			System.Drawing.Point p = new System.Drawing.Point((int)x.GetDouble(),(int)y.GetDouble());
			DrawMgr.DrawCircle(p,(int)r.GetDouble(),!(bool)outline);
		}
		#endregion
		
		#region Rooms
		public static void room_goto(GmlVar numb)
		{
			RoomMgr.Instance.GoTo(ResourceMgr.Instance.GetRoom(numb));
		}
		#endregion

		#region Others
		public static void show_message(GmlVar str)
		{
			System.Windows.Forms.MessageBox.Show(str.ToString());
		}
		
		public static void game_end()
		{
			WindowMgr.Instance.Exit();
		}
		public static void instance_create(GmlVar x,GmlVar y, GmlVar obj)
		{
			ResourceMgr.Instance.CreateInstance((int)obj.GetDouble(), (int)x.GetDouble(), (int)y.GetDouble());
		}
		#endregion
		
		#region Globals
		public static real fps
		{
			get
			{
				return WindowMgr.Instance.Fps;
			}
		}
		public static Room room
		{
			get
			{
				return RoomMgr.Instance.CurrentRoom;
			}
		}
		public static string room_caption
		{
			get
			{
				return RoomMgr.Instance.CurrentRoom.caption;
			}
			set
			{
				RoomMgr.Instance.CurrentRoom.caption = value;
			}
		}
		public static real room_speed
		{
			get
			{
				return RoomMgr.Instance.CurrentRoom.room_speed;
			}
			set
			{
				RoomMgr.Instance.CurrentRoom.room_speed = (int)value;
			}
		}
		public static real pi
		{
			get
			{
				return System.Math.PI;
			}
		}
		public static real mouse_x
		{
			get
			{
				return WindowMgr.Instance.MousePosition.X;
			}
		}
		public static real mouse_y
		{
			get
			{
				return WindowMgr.Instance.MousePosition.Y;
			}
		}
		public static System.Drawing.Color c_black =  System.Drawing.Color.Black;
		public static System.Drawing.Color c_white =  System.Drawing.Color.White;
		public static System.Drawing.Color c_red =  System.Drawing.Color.Red;
		public static System.Drawing.Color c_blue =  System.Drawing.Color.Blue;
		public static System.Drawing.Color c_yellow =  System.Drawing.Color.Yellow;
		public static System.Drawing.Color c_green =  System.Drawing.Color.Green;
		public static real vk_nokey = 0;
		public static real vk_anykey = 1;
		public static real vk_left = 37;
		public static real vk_right = 39;
		public static real vk_up = 38;
		public static real vk_down = 40;
		public static real vk_enter = 13;
		public static real vk_escape = 27;
		public static real vk_space = 32;
		public static real vk_shift = 16;
		public static real vk_control = 17;
		public static real vk_alt = 18;
		public static real vk_backspace = 8;
		public static real vk_tab = 9;
		public static real vk_home = 36;
		public static real vk_end = 35;
		public static real vk_delete = 46;
		public static real vk_insert = 45;
		public static real vk_pageup = 33;
		public static real vk_pagedown = 34;
		public static real vk_pause = 19;
		public static real vk_printscreen = 44;
		public static real vk_f1 = 112;
		public static real vk_f2 = 113;
		public static real vk_f3 = 114;
		public static real vk_f4 = 115;
		public static real vk_f5 = 116;
		public static real vk_f6 = 117;
		public static real vk_f7 = 118;
		public static real vk_f8 = 119;
		public static real vk_f9 = 120;
		public static real vk_f10 = 121;
		public static real vk_f11 = 122;
		public static real vk_f12 = 123;
		public static real vk_numpad0 = 96;
		public static real vk_numpad1 = 97;
		public static real vk_numpad2 = 98;
		public static real vk_numpad3 = 99;
		public static real vk_numpad4 = 100;
		public static real vk_numpad5 = 101;
		public static real vk_numpad6 = 102;
		public static real vk_numpad7 = 103;
		public static real vk_numpad8 = 104;
		public static real vk_numpad9 = 105;
		public static real vk_multiply = 106;
		public static real vk_divide = 111;
		public static real vk_add = 107;
		public static real vk_subtract = 109;
		public static real vk_decimal = 110;
		public static real vk_lshift = 160;
		public static real vk_lcontrol = 162;
		public static real vk_lalt = 164;
		public static real vk_rshift = 161;
		public static real vk_ralt = 165;
		public static real vk_rcontrol = 163;
		#endregion
	}
}